<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../css/reset.css">
    <style>
        li {
            line-height: 40px;
            border: 1px dashed #333;
        }

        .button-groups {
            margin-top: 10px;
        }

        .active {
            background-color: pink;
        }
    </style>
</head>

<body>
    <div class="wrap">
        <h2 id="title">模拟封装jqeury</h2>
        <ul class="list">
            <li class="first active">01</li>
            <li>02</li>
            <li>03</li>
            <li>04</li>
            <li>05</li>
            <li class="last">06</li>
        </ul>
    </div>

    <div class="button-groups">
        <button class="html">html</button>
        <button class="hide">hide</button>
        <button class="show">show</button>
        <button class="click">click</button>
        <button class="addClass">addClass</button>
        <button class="removeClass">removeClass</button>
        <button class="hasClass">hasClass</button>
        <button class="setWidth">设置宽度</button>
        <button class="getWidth">获取宽度</button>
        <button class="attr">attr</button>
        <button class="prop">prop</button>
        <button class="css">css</button>
        <button class="eq">eq</button>
        <button class="siblings">siblings</button>
        <button class="chain">链式操作</button>
    </div>
</body>
<script>

    // 获取元素 根据传入的css选择器得到一个伪数组,可以使用GetEle.prototype的属性和方法
    function GetEle(selector) {
        var list = [];

        if (typeof selector === "string") {  // css选择器
            list = document.querySelectorAll(selector);
        } else if (selector instanceof Element) { // 单个元素DOM元素
            list = [selector];  // 将元素放到数组中 [li]
        } else if (selector.length) { // 多个元素DOM元素的集合
            list = selector;  // 
        } else if (typeof selector == "function") {

        } else {
            list = [...arguments];
        }

        list = Array.from(list);  // 转为真数组 
        Object.setPrototypeOf(list, GetEle.prototype);  // 再改为伪数组

        return list; // [ele,ele,ele,ele]
    }

    // prototype 原型对象方法  => 所有的实例化对象均可使用
    // GetEle.prototype.setText = function (con) {
    //     // this => 指向调用此方法的实例化对象  // 伪数组  [li,li,li,li]
    //     for (var i = 0; i < this.length; i++) {
    //         var ele = this[i];
    //         ele.textContent = con;
    //     }
    // }

    // GetEle.prototype.getText = function () {
    //     // this => 指向调用此方法的实例化对象  // 伪数组  [li,li,li,li]
    //     return this[0].textContent;
    // }

    // text()  可以获取和设置集合中元素的文本内容
    // text(111)  有参数就设置
    // text()     没有参数就获取
    GetEle.prototype.text = function (con) {
        // this => 指向调用此方法的实例化对象 
        if (arguments.length >= 1) {
            // for (var i = 0; i < this.length; i++) {
            //     var ele = this[i];
            //     ele.textContent = con;
            // }

            this.each(function (ele, index) {
                ele.textContent = con;
            })
            return this;
        } else {
            return this[0].textContent;
        }
    }

    GetEle.prototype.html = function (con) {
        // this => 指向调用此方法的实例化对象
        if (arguments.length >= 1) {
            // for (var i = 0; i < this.length; i++) {
            //     var ele = this[i];
            //     ele.innerHTML = con;
            // }
            this.each(function (ele, index) {
                ele.innerHTML = con;
            })
            return this;
        } else {
            return this[0].innerHTML;
        }
    }

    GetEle.prototype.val = function (con) {
        // this => 指向调用此方法的实例化对象
        if (arguments.length >= 1) {
            // for (var i = 0; i < this.length; i++) {
            //     var ele = this[i];
            //     ele.value = con;
            // }

            this.each(function (ele, index) {
                ele.value = con;
            })
            return this;
        } else {
            return this[0].value;
        }
    }

    GetEle.prototype.hide = function () {
        //  this => 指向调用此方法的实例化对象
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.style.display = "none";
        // }

        this.each(function (ele, index) {
            ele.style.display = "none";
        })
        return this;
    }

    GetEle.prototype.show = function () {
        //  this => 指向调用此方法的实例化对象
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.style.display = "block";
        // }

        this.each(function (ele, index) {
            ele.style.display = "block";
        })
        return this;
    }

    GetEle.prototype.on = function (type, handerFn) {
        //  this => 指向调用此方法的实例化对象
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.addEventListener(type, handerFn);
        // }

        this.each(function (ele, index) {
            ele.addEventListener(type, handerFn);
        })
        return this;
    }

    GetEle.prototype.off = function (type, handerFn) {
        //  this => 指向调用此方法的实例化对象
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.removeEventListener(type, handerFn);
        // }

        this.each(function (ele, index) {
            ele.removeEventListener(type, handerFn);
        })
        return this;
    }

    GetEle.prototype.click = function (handerFn) {
        //  this => 指向调用此方法的实例化对象
        this.on("click", handerFn);
        return this;
    }

    GetEle.prototype.each = function (handerFn) {
        // this -> 调用此方法的实例化对象
        for (var i = 0; i < this.length; i++) {
            var item = this[i];
            var index = i;
            handerFn(item, index);
        }
        return this;
    }


    GetEle.prototype.addClass = function (classStr) {
        //  this => 指向调用此方法的实例化对象
        var list = classStr.split(" ");
        this.each(function (ele, index) {
            // ele.classList.add("one","two","three");
            ele.classList.add(...list);
            // ele.classList.add.apply(null, list);
        })
        return this;
    }

    GetEle.prototype.removeClass = function (classStr) {
        //  this => 指向调用此方法的实例化对象
        // debugger;
        var list = classStr.split(" ");
        this.each(function (ele, index) {
            // ele.classList.remove("one","two","three");
            ele.classList.remove(...list);
            // ele.classList.remove.apply(null, list);
        })
        return this;
    }

    // hasClass()  判断集合中是否存在某个class名
    // 只要集合中有一个存在该class名即可 => 包含
    GetEle.prototype.hasClass = function (className) {
        //  this => 指向调用此方法的实例化对象
        var flag = false; //假设不存在
        this.each(function (ele, index) {
            if (ele.classList.contains(className)) {
                flag = true;
            }
        })
        return flag;
    }

    GetEle.prototype.width = function (val) {
        //  this => 指向调用此方法的实例化对象
        if (arguments.length >= 1) {
            this.each(function (ele, index) {

                // val  
                // 可能有单位  200px 200% 200em 200rem 200pt 200vw 200vh 200vmin 200vmax
                // 也能没有单位 200 

                var unitReg = /^\d+(px|%|em|rem|pt|vw|vh|vmin|vmax)$/;

                if (unitReg.test(val)) {
                    ele.style.width = val;
                } else {
                    ele.style.width = val + "px";
                }

            })
            return this;
        } else {
            // return this[0].style.width;  // style只能获取行内样式
            return parseFloat(this.getCss("width"));

        }
    }
    GetEle.prototype.height = function (val) {
        //  this => 指向调用此方法的实例化对象
        if (arguments.length >= 1) {
            this.each(function (ele, index) {

                // val  
                // 可能有单位  200px 200% 200em 200rem 200pt 200vw 200vh 200vmin 200vmax
                // 也能没有单位 200 

                var unitReg = /^\d+(px|%|em|rem|pt|vw|vh|vmin|vmax)$/;

                if (unitReg.test(val)) {
                    ele.style.height = val;
                } else {
                    ele.style.height = val + "px";
                }

            })
            return this;
        } else {
            // return this[0].style.height;  // style只能获取行内样式
            return parseFloat(this.getCss("height"));

        }
    }

    GetEle.prototype.getCss = function (cssAttr) {
        //  this => 指向调用此方法的实例化对象
        if (window.getComputedStyle) {
            return window.getComputedStyle(this[0])[cssAttr];
        } else {
            return this[0].currentStyle[cssAttr];
        }
    }

    // attr()   获取和设置属性节点(标签内的属性)
    // attr("class","one")   => ele.setAttribute("class","one")
    // attr("class")   => ele.getAttribute("class")
    GetEle.prototype.attr = function (key, val) {
        if (arguments.length >= 2) {
            this.each(function (ele, index) {
                ele.setAttribute(key, val);
            })
            return this;
        } else if (arguments.length >= 1) {
            return this[0].getAttribute(key);
        }
    }

    // prop()   获取和设置元素节点的属性(元素节点 => 对象 => 属性和方法 )
    // prop("className","one")   => ele.className = "one"
    // prop("className")   => ele.className
    GetEle.prototype.prop = function (key, val) {
        if (arguments.length >= 2) {
            this.each(function (ele, index) {
                ele[key] = val;
            })
            return this;
        } else if (arguments.length >= 1) {
            return this[0][key];
        }
    }

    // css()   获取和设置元素节点的属性(元素节点 => 对象 => 属性和方法 )
    // css("width","100px")   => ele.style.width = "100px"
    // css("width")           => getComputedStyle(ele)["width"]
    GetEle.prototype.css = function (cssKey, cssVal) {
        if (arguments.length >= 2) {
            this.each(function (ele, index) {
                ele.style[cssKey] = cssVal;
            })
        } else if (arguments.length >= 1) {
            if (typeof cssKey === "string") {
                return this.getCss(cssKey);
            } else if (cssKey instanceof Object) {
                for (var key in cssKey) {
                    var val = cssKey[key];
                    this.css(key, val);
                }

            }
        }
        return this;
    }

    // 链式操作 => 方法的返回值还是同种类型的数据
    // "YYYY-MM-DD".replace().replace().replace()

    // var s = new Set();
    // s.add(1).add(2).add(3)

    // eq(index) 返回集合中对应下标的元素形成的实例化对象
    // $(".list li").eq(0).css({ background: "red" })
    GetEle.prototype.eq = function (index) {
        //  this => 指向调用此方法的实例化对象
        // return this[index]; // 返回对应下标的原生dom元素
        return $(this[index]); // 返回对应下标的元素形成实例化对象
    }

    // siblings()  集合中每一个被选中的元素的 同级元素形成的集合

    // $(".first").siblings().css({ background: "red" })
    // $(".first,.last").siblings().css({ background: "red" })

    GetEle.prototype.siblings = function (index) {
        //  this => 指向调用此方法的实例化对象
        var list = [];
        this.each(function (ele, index) { // ele => 每一个元素
            var parentEle = ele.parentElement;// 找父元素
            var children = parentEle.children; // 父元素的所有子元素

            // 从所有的子元素中 找到 ele的同级元素
            var subArr = Array.from(children).filter(item => item != ele);
            list = list.concat(subArr);
        })
        list = [...new Set(list)];

        return $(list);
    }

    // 获取匹配的元素 相对于同级的下标
    // $(".last").index();
    GetEle.prototype.index = function (index) {
        //  this => 指向调用此方法的实例化对象
        var ele = this[0]; // 默认获取集合中的第一个元素

        var parentEle = ele.parentElement;// 找父元素
        var children = parentEle.children; // 父元素的所有子元素

        // ele 被选中的元素在集合中的下标
        var index = Array.from(children).findIndex(item => item === ele);
        return index;
    }






    function $(selector) {
        return new GetEle(selector);
    }


    $(".html").click(function () {
        $(".list li").html("hello");
    })

    $(".hide").click(function () {
        $(".list li").hide();
    })

    $(".show").click(function () {
        $(".list li").show();
    })

    $(".click").click(function () {
        $(".list li").click(function () {
            console.log(this);
        });
    })

    $(".addClass").click(function () {
        $(".list li").addClass("one two three");
    })

    $(".removeClass").click(function () {
        $(".list li").removeClass("one three");
    })

    $(".hasClass").click(function () {
        console.log($(".list li").hasClass("two"));;
    })

    $(".setWidth").click(function () {
        // $(".list li").width("200px");
        $(".list li").width(200);
    })

    $(".getWidth").click(function () {
        console.log($(".list li").width());
    })

    $(".attr").click(function () {
        $(".list li").attr("class", "one two three");
        $(".list li").attr("title", "hello");
        $(".list li").attr("asd", "asd");
        $(".list li").attr("data-index", "1111");

        console.log($(".list li").attr("class"));
        console.log($(".list li").attr("title"));
        console.log($(".list li").attr("asd"));
        console.log($(".list li").attr("data-index"));
    })

    $(".prop").click(function () {
        // $(".list li").prop("id", "aaaa");
        // $(".list li").prop("className", "one two three");
        // $(".list li").prop("title", "hello world");
        // $(".list li").prop("tagName", "hello");
        // $(".list li").prop("style", "width:100px");

        console.log($(".list li").prop("id"));
        console.log($(".list li").prop("className"));
        console.log($(".list li").prop("tagName"));
        console.log($(".list li").prop("innerHTML"));
        console.log($(".list li").prop("innerText"));
        console.log($(".list li").prop("clientWidth"));
        console.log($(".list li").prop("offsetLeft"));
    })


    $(".css").click(function () {
        // $(".list li").css("background", "red");
        // $(".list li").css("width", "200px");
        // $(".list li").css("height", "200px");
        // $(".list li").css("text-align", "center");
        // $(".list li").css("line-height", "200px");

        $(".list li").css({
            background: "red",
            width: "200px",
            height: "200px",
            textAlign: "center",
            lineHeight: "200px"
        })

        console.log($(".list li").css("background"));
        console.log($(".list li").css("width"));
        console.log($(".list li").css("height"));
        console.log($(".list li").css("text-align"));
        console.log($(".list li").css("line-height"));
    })


    $(".eq").click(function () {
        $(".list li").eq(0).css({ background: "red" })
    })
    $(".siblings").click(function () {
        // $(".first").siblings().css({ background: "red" })
        $(".first,.last").siblings().css({ background: "red" })
    })


    $(".chain").click(function () {
        $(".list li").eq(0).html(123123).width(200).css({ background: "red" }).click(function () {
            alert($(this).index());
        }).siblings().html(456456).width(400).css({ background: "blue" }).click(function () {
            alert($(this).index());
        })
    })



    $(".list li").click(function () {
        // console.log(this);
        // console.log(this.innerHTML);

        // this=> 原生DOM元素 => 只能使用原生的属性和方法 =>  无法使用GetEle.prototype上的方法 !!!!
        // this.html();   //  html is not defined

        // 如果想使用GetEle.prototype上的方法 => 想方法将原生dom元素转化为对应的实例化对象
        // debugger;
        // $(this).css({
        //     background: "red"
        // }).siblings().css({
        //     background: "none"
        // })

        $(this).addClass("active").siblings().removeClass("active");
    })













</script>

</html>